// Copyright (C) 2007 Blue Onion Software
// All rights reserved

using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using System.Web.Security;

namespace BlueOnionSoftware.Bloget
{
    public class User : MembershipUser
    {
    }

#if false
    public enum Role { None = 0, Author = 1, Administrator = 2 };

    [XmlRoot(ElementName = "user", Namespace = Blog.NamespaceUri)]
    public class User : MembershipUser, IEquatable<User>
    {
        internal const string DefaultUser = "admin";
        internal const string DefaultPassword = "21-23-2F-29-7A-57-A5-A7-43-89-4A-0E-4A-80-1F-C3"; // admin;
        internal const string DefaultSalt = "";
        internal const string DefaultEmail = "example@example.com";

        Guid id = Guid.NewGuid();
        string name = string.Empty;
        string password = string.Empty;
        string salt = string.Empty;
        Role role = Role.None;

        public User()
        {
        }

        static internal User CreateAdmin()
        {
            User user = new User();
            user.name = DefaultUser;
            user.password = DefaultPassword;
            user.salt = DefaultSalt;
            user.Email = DefaultEmail;
            user.LastLoginDate = DateTime.UtcNow;
            user.role = Role.Administrator;
            return user;
        }

        public User(User user)
        {
            id = user.id;
            name = user.name;
            password = user.password;
            salt = user.salt;
            Email = user.Email;
            LastLoginDate = user.LastLoginDate;
            role = user.role;
        }

        [XmlElement("id")]
        public Guid Id
        {
            get { return id; }
            set { id = value; }
        }

        [XmlIgnore]
        public override object ProviderUserKey
        {
            get { return id; }
        }

        [XmlIgnore]
        public override string ProviderName
        {
            get { return base.ProviderName; }
        }

        [XmlElement("name")]
        public string Name
        {
            get { return name ?? string.Empty; }

            set
            {
                if (ValidateString(value) == false)
                {
                    throw new ArgumentException("Invalid name format", value);
                }

                name = value.Trim();
            }
        }

        [XmlIgnore]
        public override string UserName
        {
            get { return Name; }
        }

        [XmlElement("password")]
        public string Password
        {
            get
            {
                return password;
            }

            set
            {
                if (ValidateString(value) == false)
                {
                    throw new ArgumentException("Invalid password foramt", "value");
                }

                password = value.Trim();
            }
        }

        [XmlElement("salt")]
        public string Salt
        {
            get { return salt; }
            set { salt = value ?? string.Empty; }
        }

        [XmlElement("email")]
        public string UserEmail
        {
            get { return Email; }
            set { Email = value; }
        }

        [XmlIgnore]
        public override string Email
        {
            get { return base.Email ?? string.Empty; }
            set { base.Email = value; }
        }

        [XmlElement("last-logon")]
        public DateTime LastLogOn
        {
            get { return base.LastLoginDate; }
            set { base.LastLoginDate = value; }
        }

        [XmlElement("role")]
        public Role UserRole
        {
            get { return role; }
            set { role = value; }
        }

        internal bool ValidatePassword(string passwordArg)
        {
            if (ValidateString(passwordArg) == false)
            {
                return false;
            }

            return (Password == ComputeMessageDigest(passwordArg, Salt));
        }

        internal void EncodePassword(string passwordArg)
        {
            if (ValidateString(passwordArg) == false)
            {
                throw new ArgumentException("password format is not valid", "passwordArg");
            }

            Salt = Path.GetRandomFileName();
            Password = ComputeMessageDigest(passwordArg.Trim(), Salt);
        }

        static internal bool IsValidName(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return false;
            }

            if (char.IsWhiteSpace(name[0]) || char.IsWhiteSpace(name[name.Length - 1]))
            {
                return false;
            }

            foreach (char c in name)
            {
                if (char.IsLetterOrDigit(c) == false && char.IsWhiteSpace(c) == false)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Checks if string not null and not empty or composed entirely of whitespace.
        /// </summary>
        /// <param name="item">string to test</param>
        /// <returns>bool</returns>
        static internal bool ValidateString(string item)
        {
            if (string.IsNullOrEmpty(item) == false)
            {
                return string.IsNullOrEmpty(item.Trim()) == false;
            }

            return false;
        }

        internal bool IsValid()
        {
            return IsValidName(name) && ValidateString(password);
        }

        internal static string ComputeMessageDigest(string message, string salt)
        {
            if (ValidateString(message) == false)
            {
                throw new ArgumentNullException("message");
            }

            if (salt == null) // OK to be empty
            {
                throw new ArgumentNullException("salt");
            }

            MD5 md5 = MD5.Create();
            byte[] bytes = md5.ComputeHash(Encoding.Default.GetBytes(message + salt));
            string messageDigest = BitConverter.ToString(bytes);
            return messageDigest;
        }

        public bool Equals(User other)
        {
            return (other != null && other.id.CompareTo(id) == 0);
        }

        [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
        public override bool Equals(object obj)
        {
            return (obj is User && Equals((User)obj));
        }

        public override int GetHashCode()
        {
            return id.GetHashCode();
        }

        static internal User CreateNewUser()
        {
            User user = new User();
            Random random = new Random();
            user.Name = "user" + random.Next(9999);
            user.Password = DefaultPassword;
            return user;
        }
    }
#endif
}
